# = Class ASTRange
# Inherits from AST. Represents the implementation of an AST especifically designed
# for renges of the programming language Vectorinox
# == Attributes inherited from AST
# node, children
# == Methods inherited from AST
# check(), run()
class ASTRange < AST
  
  # * left: Left operand of the range
  attr_reader :left
  # * right: Right operand of the range
  attr_reader :right
  # If it's a range or a position
  attr_reader :type
  # Value resulting of the dynamic evaluation of the range
  attr_reader :value
  
  # Constructor of the class
  # === Parameters
  # * left: Left operand of the range
  # * right: Right operand of the range
  def initialize left, right
    @left = left
    @right = right
  end

  # Method to evaluate the range
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the parent AST
  def eval parent_sym_table, func_table
    @value = [nil, nil]
    if nil != @left
      msg = @left.eval parent_sym_table, func_table
      if nil != msg
        return msg
      end
      @value[0] = @left.value.to_i
      if @value[0] <= 0
        return "Valor de rango izquierdo debe ser positivo, encontrado '#{@left.value}' (#{@left.error_location})"
      end
      if @value[0] != @left.value
        return "Valor de rango izquierdo debe ser entero '#{@left.value}' (#{@left.error_location})"
      end
    end
    if nil != @right
      msg = @right.eval parent_sym_table, func_table
      if nil != msg
        return msg
      end
      @value[1] = @right.value.to_i
      if @value[1] <= 0
        return "Valor de rango derecho debe ser positivo, encontrado '#{@right.value}' (#{@right.error_location})"
      end
      if @value[1] != @right.value
        return "Valor de rango derecho debe ser entero '#{@right.value}' (#{@right.error_location})"
      end
    end
    if nil != @left && nil != @right
      if @right.value < @left.value
        return "El rango está mal definido '#{@left.value}-#{@right.value}' (#{error_location})"
      end
    end
    nil
  end
  
  # Method to check the static correctitude of the range
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the pare
  # * func_type: Type of valid return value
  def check parent_sym_table, func_table, func_type
    if nil != @left
      msg = @left.check parent_sym_table, func_table, func_type
      if nil != msg
        return msg
      end
      if 'num' != @left.type
        return "Valor izquierdo de rango debe ser un número, se encontró " +
               "'#{@left.type}' (#{@left.error_location})"
      end
    end
    if nil != @right
      msg = @right.check parent_sym_table, func_table, func_type
      if nil != msg
        return msg
      end
      if 'num' != @right.type
        return "Valor derecho de rango debe ser un número, se encontró " +
               "'#{@right.type}' (#{@right.error_location})"
      end
    end

    # The only way this is a position is that begin-end positions are the same
    if nil != @left && @left == @right
      @type = 'position'
      return
    end

    @type = 'range'
    nil
  end

  # Returns the closest wrong token to the place were an error is generated
  def error_tk
    tk = nil != @left ? @left.error_tk : nil
    if nil != tk
      return tk
    end
    nil != @right ? @right.error_tk : nil
  end

  # Creates a 'String' representation of the AST with 'i' identation spaces
  # === Parameters
  # * i: Identation with which the AST should be printed with
  def to_s i
    im = i + @@c
    left = @left == nil ? "()" : @left.to_s(im)
    right = @right == nil ? "()" : @right.to_s(im)
    "(Rango\n#{im}#{left}\n#{im}#{right}\n#{i})"
  end
end